package com.douqu.game.battle.util;

import com.douqu.game.battle.controller.BattleController;
import com.douqu.game.battle.controller.EVEController;
import com.douqu.game.battle.controller.PVEController;
import com.douqu.game.battle.controller.PVPController;
import com.douqu.game.battle.controller.sprite.MonsterController;
import com.douqu.game.battle.controller.sprite.PlayerController;
import com.douqu.game.battle.controller.sprite.SpriteController;
import com.douqu.game.battle.entity.aobject.BattleAObject;
import com.douqu.game.battle.entity.aobject.LastSendPosition;
import com.douqu.game.battle.entity.tmp.SpriteBattleTmp;
import com.douqu.game.battle.server.BattleInitInfo;
import com.douqu.game.battle.server.GameServer;
import com.douqu.game.core.astar.Node;
import com.douqu.game.core.config.common.Position;
import com.douqu.game.core.e.E_BattleDetailType;
import com.douqu.game.core.entity.Player;
import com.douqu.game.core.entity.battle.BattleResultParam;
import com.douqu.game.core.entity.db.CardDB;
import com.douqu.game.core.entity.ext.SettingInfo;
import com.douqu.game.core.protobuf.SGCommonProto;
import com.douqu.game.core.protobuf.SGMainProto;
import com.douqu.game.core.protobuf.SGWarProto;
import com.douqu.game.core.util.LogUtils;

import java.rmi.RemoteException;
import java.util.List;

/**
 * @Author: Bean
 * @Description:
 * @Date: 2017-12-23 16:50
 */
public class MsgUtils {


    public static void sendBattleResult(SpriteController spriteController, SpriteController targetController, SGCommonProto.E_BATTLE_TYPE battleType, int winTeam, BattleResultParam resultParam, int star) {
        if (spriteController instanceof PlayerController && spriteController.isOnlinePlayer()) {
            PlayerController playerController = (PlayerController) spriteController;

            SGWarProto.S2C_SynResult.Builder data = SGWarProto.S2C_SynResult.newBuilder();
            data.setWinTeam(winTeam);
            data.setStar(star);
            data.setKey(playerController.getPlayer().getEncodeKey());
            playerController.sendMsg(SGMainProto.E_MSG_ID.MsgID_War_SynResult_VALUE, data.build().toByteArray());

            SGWarProto.S2C_BattleResult.Builder result = SGWarProto.S2C_BattleResult.newBuilder();
            boolean win = winTeam == playerController.getAttachment().getTeamNo();
            result.setWin(win);
            result.setBattleType(battleType);
            result.setKey(playerController.getPlayer().getEncodeKey());
            result.addAllDamageObj(playerController.getAttachment().parseDamageList(5));
            result.addAllDamageObj(targetController.getAttachment().parseDamageList(5));
            result.setTotalDamage(playerController.getAttachment().getTotalDamage());

            if (battleType == SGCommonProto.E_BATTLE_TYPE.BATTLE_TYPE_WORLD_BOSS) {
                if (resultParam != null)
                    result.addAllReward(resultParam.parseList());
            } else {
                if (win) {
                    if (resultParam != null)
                        result.addAllReward(resultParam.parseList());
                    if (battleType == SGCommonProto.E_BATTLE_TYPE.BATTLE_TYPE_SPAN_CAMP) {
                        result.setCampWin(playerController.getAttachment().getCampBattleWin());
                        result.setCampLose(SGCommonProto.BattleResultCampLose.newBuilder());//防止客户端不显示结算界面
                    }
                } else {
                    if (battleType == SGCommonProto.E_BATTLE_TYPE.BATTLE_TYPE_SPAN_CAMP) {
                        result.setCampLose(playerController.getAttachment().getCampBattleLose(resultParam));
                        result.setCampWin(SGCommonProto.BattleResultCampWin.newBuilder());//防止客户端不显示结算界面
                    }
                }
            }

            LogUtils.info("战斗结果 -> " + result);

            playerController.sendMsg(SGMainProto.E_MSG_ID.MsgID_War_BattleResult_VALUE, result.build().toByteArray());
        }
    }


    /**
     * 通知兵相遇要开战了
     *
     * @param attacker
     * @param target
     */
    public static void sendSoldierBattleStart(BattleController battleController, BattleAObject attacker, BattleAObject target) {
        if (!battleController.getBattleDetailType().isPlayerBattle())
            return;

        sendPosition("普通攻击开战", battleController, attacker, target);

        SGWarProto.S2C_SoldierBattleStart.Builder data = SGWarProto.S2C_SoldierBattleStart.newBuilder();
        data.setAttackId(attacker.getUniqueId());
        data.setAttackPos(attacker.getPosition().parsePos());
        data.setTargetId(target.getUniqueId());
        data.setTargetPos(target.getPosition().parsePos());
        battleController.dispatchMsg(SGMainProto.E_MSG_ID.MsgID_War_SoldierBattleStart_VALUE, data.build().toByteArray());

        LogUtils.debug("两个单位开战(普通攻击) -> attacker:" + attacker + "  target:" + target);
    }


    /**
     * 通知使用技能结果
     *
     * @param skillId
     * @param releaser
     * @param targets
     */
    public static void sendUseSkill(BattleController battleController, int skillId, BattleAObject releaser, List<BattleAObject> targets, int effectTime, Position position, String skillKey) {
        if (!battleController.getBattleDetailType().isPlayerBattle())
            return;

        SGWarProto.S2C_UseSkill.Builder data = SGWarProto.S2C_UseSkill.newBuilder();
        data.setSkillId(skillId);
        data.setReleaserId(releaser.getUniqueId());

        if (targets != null) {
            for (BattleAObject battleAObject : targets) {
                if (battleAObject.isDie())
                    continue;

                data.addTargetId(battleAObject.getUniqueId());
            }
        }

        data.setEffectTime(effectTime);

        if (targets == null || data.getTargetIdCount() == 0) {
            if (position == null)
                return;
        }

        if (position != null)
            data.setTargetPos(position.parsePos());

        LogUtils.debug("使用技能 -> " + data);

        battleController.dispatchMsg(SGMainProto.E_MSG_ID.MsgID_War_UseSkill_VALUE, data.build().toByteArray());

        LogUtils.debug("sendUseSkill skillId:" + skillId + " target:" + targets + " 生效时间:" + effectTime + " 目标点:" + position + " skillKey:" + skillKey);
    }

    /**
     * 通知伤害
     *
     * @param target
     * @param damage 伤害值 负数为减血 正数为加血
     * @param hp     伤害后的血
     */
    public static void sendDamage(BattleController battleController, int sourceUniqueId, int sourceConfigId, int skillId, int target, long damage, long hp, SGCommonProto.E_DAMAGE_TYPE damageType, int buffId, String skillKey) {
        if (!battleController.getBattleDetailType().isPlayerBattle())
            return;

        if (damageType != SGCommonProto.E_DAMAGE_TYPE.DAMAGE_TYPE_MISS && damage == 0)
            return;

        LogUtils.debug("source:" + sourceUniqueId + " target:" + target + " damage:" + damage + " hp:" + hp + " skillKey:" + skillKey + " damageType:" + damageType);

        SGWarProto.S2C_DoDamage.Builder data = SGWarProto.S2C_DoDamage.newBuilder();
        data.addSpriteDamage(createDamageInfo(battleController, sourceUniqueId, sourceConfigId, skillId, target, damage, hp, damageType, buffId, skillKey));

        LogUtils.debug("damage -> " + data);

        battleController.dispatchMsg(SGMainProto.E_MSG_ID.MsgID_War_DoDamage_VALUE, data.build().toByteArray());
    }

    /**
     * 通知倒计时
     *
     * @param countdownType
     * @param time
     */
    public static void sendCountdown(BattleController battleController, SGCommonProto.E_COUNTDOWN_TYPE countdownType, int time) {
        if (!battleController.getBattleDetailType().isPlayerBattle())
            return;

        SGWarProto.S2C_SynCountDown.Builder data = SGWarProto.S2C_SynCountDown.newBuilder();
        data.setType(countdownType);
        data.setRemainTime(time);

        battleController.dispatchMsg(SGMainProto.E_MSG_ID.MsgID_War_SynCountDown_VALUE, data.build().toByteArray());
    }

    /**
     * 同步位置
     *
     * @param battleController
     */
    public static void sendPosition(String type, BattleController battleController, BattleAObject... battleAObjects) {
        if (!battleController.getBattleDetailType().isPlayerBattle())
            return;

        SGWarProto.S2C_SynPos.Builder data = SGWarProto.S2C_SynPos.newBuilder();
        for (BattleAObject battleAObject : battleAObjects) {
            if (battleAObject.isMove) {
                if (battleAObject.lastSendPos != null && !battleAObject.lastSendPos.isNeedSend(type, battleAObject.position))
                    continue;

                data.addBattleUnit(battleAObject.parseBattleUnit());
                if (battleAObject.lastSendPos == null)
                    battleAObject.lastSendPos = new LastSendPosition(type, battleAObject.position);
                else {
                    battleAObject.lastSendPos.update(type, battleAObject.position);
                }

//                List<String> list = battleController.synPosMap.get(battleAObject.getUniqueId());
//                if(list == null)
//                {
//                    list = new ArrayList<>();
//                    battleController.synPosMap.put(battleAObject.getUniqueId(), list);
//                }
//                list.add(type + "->" + battleAObject.position.toString());
            }
        }

        if (data.getBattleUnitList().size() > 0) {
            LogUtils.debug(type + " 同步位置 -> " + data);
            battleController.dispatchMsg(SGMainProto.E_MSG_ID.MsgID_War_SynPos_VALUE, data.build().toByteArray());
        }
    }


    public static SGCommonProto.SpriteDamage.Builder createDamageInfo(BattleController battleController, int sourceUniqueId, int sourceConfigId, int skillId, int target, long damage, long hp, SGCommonProto.E_DAMAGE_TYPE damageType, int buffId, String skillKey) {
        SGCommonProto.SpriteDamage.Builder spriteDamage = SGCommonProto.SpriteDamage.newBuilder();
        spriteDamage.setDamageIndex(battleController.getDamageIndex());
        spriteDamage.setSrcId(sourceUniqueId);
        spriteDamage.setSrcSkillId(skillId);
        spriteDamage.setTargetId(target);
        spriteDamage.setDamage(damage);
        spriteDamage.setHp(hp);
        spriteDamage.setSrcBuffId(buffId);
        spriteDamage.setDamageType(damageType);
        spriteDamage.setSrcConfigId(sourceConfigId);
//        spriteDamage.setSkillKey(skillKey);

        return spriteDamage;
    }


    /**
     * @param battleController
     * @param uniqueId
     * @param moveSpeed
     * @param pathList
     */
    public static void sendSoldierRoute(BattleController battleController, int uniqueId, int moveSpeed, List<Node> pathList) {
        if (!battleController.getBattleDetailType().isPlayerBattle())
            return;

        SGWarProto.S2C_SoldierRoute.Builder response = SGWarProto.S2C_SoldierRoute.newBuilder();
        response.setUniqueId(uniqueId);
        response.setMoveSpeed(moveSpeed);
        SGCommonProto.Pos.Builder pos = null;
        if (pathList != null) {
            for (Node node : pathList) {
                pos = SGCommonProto.Pos.newBuilder();
                pos.setX(node.grid.x);
                pos.setY(node.grid.y);
                response.addRoute(pos);
            }
        }

        battleController.dispatchMsg(SGMainProto.E_MSG_ID.MsgID_War_SoldierRoute_VALUE, response.build().toByteArray());
    }


    public static void createDataBattle(BattleInitInfo battleInitInfo)
    {
        try {
            BattleController battleController = null;
            switch (battleInitInfo.getBattleDetailType()) {
                case DATA_WORLD_MAP_PVP:
                    Player player = GameServer.getInstance().getIMainServer().getPlayer(battleInitInfo.getPlayer().getPlayerIndex());
                    Player target = GameServer.getInstance().getIMainServer().getPlayer(battleInitInfo.getTarget().getPlayerIndex());
                    if (player != null && target != null) {
                        battleController = new PVPController(battleInitInfo.getBattleId(),
                                new PlayerController(player, battleInitInfo.getPlayer().getServerId()),
                                new PlayerController(target, battleInitInfo.getTarget().getServerId()),
                                battleInitInfo.getBattleType(),
                                battleInitInfo.getBattleDetailType(),
                                battleInitInfo.getTarget().getPlayerIndex(),
                                battleInitInfo.getTarget().getPlayerName(),
                                battleInitInfo.getParam());
                    } else {
                        LogUtils.error("大地图数据战获取玩家数据失败 -> " + battleInitInfo);
                    }
                    break;
                case DATA_WORLD_MAP_PVG:
                case DATA_WORLD_MAP_PVE:
                    player = GameServer.getInstance().getIMainServer().getPlayer(battleInitInfo.getPlayer().getPlayerIndex());
                    if (player != null) {
                        battleController = new PVEController(battleInitInfo.getBattleId(),
                                new PlayerController(player, battleInitInfo.getPlayer().getServerId()),
                                new MonsterController(battleInitInfo.getBattleDetailType(), battleInitInfo.getTarget().getPlayerIndex(), battleInitInfo.getTarget().getServerId(), battleInitInfo.getParam()),
                                battleInitInfo.getBattleType(),
                                battleInitInfo.getBattleDetailType(),
                                battleInitInfo.getTarget().getPlayerIndex(),
                                battleInitInfo.getTarget().getPlayerName(),
                                battleInitInfo.getParam());
                    } else {
                        LogUtils.error("大地图数据战获取玩家数据失败 -> " + battleInitInfo);
                    }
                    break;
                case DATA_WORLD_MAP_EVG:
                case DATA_WORLD_MAP_EVE:
                    battleController = new EVEController(battleInitInfo.getBattleId(),
                            new MonsterController(battleInitInfo.getBattleDetailType(), battleInitInfo.getPlayer().getPlayerIndex(), battleInitInfo.getPlayer().getServerId(), battleInitInfo.getParam()),
                            new MonsterController(battleInitInfo.getBattleDetailType(), battleInitInfo.getTarget().getPlayerIndex(), battleInitInfo.getTarget().getServerId(), battleInitInfo.getParam()),
                            battleInitInfo.getBattleType(),
                            battleInitInfo.getBattleDetailType(),
                            battleInitInfo.getTarget().getPlayerIndex(),
                            battleInitInfo.getTarget().getPlayerName(),
                            battleInitInfo.getParam());
                    break;
            }

            if (battleController == null) {
                LogUtils.error("创建数据战斗错误 -> " + battleInitInfo);
                return;
            }

            battleController.init();

            GameServer.getInstance().getWorldManager().addBattleController(battleController);

            GameServer.getInstance().getWorldManager().removeBattleInitInfo(battleInitInfo);

        } catch(Exception e) {
            LogUtils.errorException(e);
        }

    }
    /**
     * 创建战斗
     * @param battleInitInfo
     * @throws RemoteException
     */
    public static void createPlayerBattle(BattleInitInfo battleInitInfo)
    {
        if(!battleInitInfo.isReady())
            return;

        try{
            //双方都准备好了，初始化战斗
            SGCommonProto.E_BATTLE_TYPE battleType = battleInitInfo.getBattleType();
            E_BattleDetailType battleDetailType = battleInitInfo.getBattleDetailType();

            LogUtils.warn("双方都准备好了 -> " + battleDetailType);

            BattleController battleController = null;
            switch (battleDetailType)
            {
                case PVE_INSTANCE:
                case PVE_OFFICIAL_RANK:
                case PVE_HERO_TEMPLE:
                case PVE_EXPEDITION:
                case PVE_SPAN_CAMP:
                case PVE_WORLD_BOSS:
                case PVE_WORLD_MAP:
                    battleController = new PVEController(battleInitInfo.getBattleId(),
                            battleInitInfo.getPlayer().getPlayer(),
                            new MonsterController(battleDetailType, battleInitInfo.getTarget().getPlayerIndex(), battleInitInfo.getTarget().getServerId(), battleInitInfo.getParam()),
                            battleType, battleDetailType,
                            battleInitInfo.getTarget().getPlayerIndex(), battleInitInfo.getTarget().getPlayerName(),
                            battleInitInfo.getParam());
                    break;
                case PVP_AI_ARENA:
                case PVP_AI_OFFICIAL_RANK:
                case PVP_AI_MAJOR:
                    Player offlinePlayer = GameServer.getInstance().getIMainServer().getOfflinePlayer(battleInitInfo.getTargetPlayerIndex());
                    if(offlinePlayer != null)
                    {
                        battleController = new PVPController(battleInitInfo.getBattleId(),
                                battleInitInfo.getPlayer().getPlayer(),
                                new PlayerController(offlinePlayer, battleInitInfo.getTarget().getServerId()),
                                battleType, battleDetailType,
                                battleInitInfo.getTarget().getPlayerIndex(), battleInitInfo.getTarget().getPlayerName(),
                                battleInitInfo.getParam());
                    }
                    else
                    {
                        LogUtils.error("获取离线玩家数据失败 -> " + battleInitInfo.getTarget());
                    }
                    break;
                case PVP_DATA_SPAN_CAMP:
                case PVP_DATA_WORLD_MAP:
                    Player targetPlayer = GameServer.getInstance().getIMainServer().getPlayer(battleInitInfo.getTargetPlayerIndex());
                    if(targetPlayer != null)
                    {
                        battleController = new PVPController(battleInitInfo.getBattleId(),
                                battleInitInfo.getPlayer().getPlayer(),
                                new PlayerController(targetPlayer, battleInitInfo.getTarget().getServerId()),
                                battleType, battleDetailType,
                                battleInitInfo.getTarget().getPlayerIndex(), battleInitInfo.getTarget().getPlayerName(),
                                battleInitInfo.getParam());
                    }
                    else
                    {
                        LogUtils.error("获取玩家数据失败 -> " + battleInitInfo.getTarget());
                    }
                    break;
                case PVP_SPAN_CAMP:
                case PVP_WORLD_MAP:
                    battleController = new PVPController(battleInitInfo.getBattleId(),
                            battleInitInfo.getPlayer().getPlayer(),
                            battleInitInfo.getTarget().getPlayer(),
                            battleType, battleDetailType,
                            battleInitInfo.getTarget().getPlayerIndex(), battleInitInfo.getTarget().getPlayerName(),
                            battleInitInfo.getParam());
                    break;
            }

            if(battleController == null)
            {
                LogUtils.error("创建战斗错误 -> " + battleInitInfo);
                return;
            }

            LogUtils.info("双方都准备好了，初始化战斗成功 -> " + battleController);
            battleController.init();

            if(battleController.getBattleDetailType().isPlayerBattle())
            {
                SpriteBattleTmp playerBattleTmp = battleController.getSource().getAttachment();
                SpriteBattleTmp targetBattleTmp = battleController.getTarget().getAttachment();
                BattleAObject playerMaster = playerBattleTmp.getMasterSoldier();
                BattleAObject targetMaster = targetBattleTmp.getMasterSoldier();

                boolean bothIsPlayer = battleController.getBattleDetailType().isBothPlayer();

                SGWarProto.S2C_Create.Builder response = SGWarProto.S2C_Create.newBuilder();
                response.setBattleType(battleInitInfo.getBattleType());
                response.setSelftMaster(playerMaster.parseBattleUnit(playerBattleTmp.parseBaseInfo()));
                response.setOtherMaster(targetMaster.parseBattleUnit(targetBattleTmp.parseBaseInfo(battleInitInfo.getTarget().getPlayerName())));
                response.setIsRealPlayerBattle(bothIsPlayer);

                SpriteController spriteController = battleController.getSource();
                if(spriteController instanceof PlayerController)
                {
                    SettingInfo settingInfo = ((PlayerController) spriteController).getPlayer().getExtInfo(SettingInfo.class);
                    response.addAllSelfMasterSkill(settingInfo.getEquipSkillIds());
                }

                List<CardDB> cardList = playerBattleTmp.getCardList();
                for(CardDB cardDB : cardList)
                {
                    response.addBattleCardId(cardDB.id);
                }

                LogUtils.info("create -> teamNo1 -> " + response);

                LogUtils.warn("队伍1 -> " + battleController.getSource() + " 　返回create消息");
                battleController.getSource().sendMsg(SGMainProto.E_MSG_ID.MsgID_War_Create_VALUE, response.build().toByteArray());

                if(battleController.getTarget() instanceof PlayerController && battleController.getTarget().isOnlinePlayer())
                {
                    response = SGWarProto.S2C_Create.newBuilder();
                    response.setBattleType(battleInitInfo.getBattleType());
                    response.setSelftMaster(targetMaster.parseBattleUnit(targetBattleTmp.parseBaseInfo()));
                    response.setOtherMaster(playerMaster.parseBattleUnit(playerBattleTmp.parseBaseInfo()));
                    response.setIsRealPlayerBattle(bothIsPlayer);

                    Player targetPlayer = ((PlayerController) battleController.getTarget()).getPlayer();
                    SettingInfo settingInfo = targetPlayer.getExtInfo(SettingInfo.class);
                    response.addAllSelfMasterSkill(settingInfo.getEquipSkillIds());

                    cardList = targetBattleTmp.getCardList();
                    for(CardDB cardDB : cardList)
                    {
                        response.addBattleCardId(cardDB.id);
                    }

                    LogUtils.info("create -> teamNo2 -> " + response);
                    LogUtils.warn("队伍2 -> " + battleController.getTarget() + " 　返回create消息");

                    battleController.getTarget().sendMsg(SGMainProto.E_MSG_ID.MsgID_War_Create_VALUE, response.build().toByteArray());
                }
            }

            GameServer.getInstance().getWorldManager().addBattleController(battleController);

            GameServer.getInstance().getWorldManager().removeBattleInitInfo(battleInitInfo);

        }catch (Exception e){
            LogUtils.errorException(e);
        }
    }


}
